package org.dromara.web.service.impl

import cn.dev33.satoken.stp.StpUtil
import cn.hutool.core.collection.CollUtil
import io.github.oshai.kotlinlogging.KotlinLogging
import org.dromara.common.core.domain.model.LoginUser
import org.dromara.common.core.domain.model.SocialLoginBody
import org.dromara.common.core.exception.ServiceException
import org.dromara.common.core.utils.StreamUtils
import org.dromara.common.core.utils.ValidatorUtils.validate
import org.dromara.common.json.utils.JsonUtils
import org.dromara.common.satoken.utils.LoginHelper
import org.dromara.common.social.config.properties.SocialProperties
import org.dromara.common.social.utils.SocialUtils
import org.dromara.common.tenant.helper.TenantHelper
import org.dromara.system.domain.SysUser
import org.dromara.system.domain.vo.SysClientVo
import org.dromara.system.domain.vo.SysSocialVo
import org.dromara.system.mapper.SysUserMapper
import org.dromara.system.service.ISysSocialService
import org.dromara.web.domain.vo.LoginVo
import org.dromara.web.service.IAuthStrategy
import org.dromara.web.service.SysLoginService
import org.springframework.stereotype.Service

/**
 * 第三方授权策略
 *
 *@author LikeYouDo
 *@date 2025/1/5 21:02
 */
@Service("social" + IAuthStrategy.BASE_NAME)
class SocialAuthStrategy(
    private val socialProperties: SocialProperties,
    private val sysSocialService: ISysSocialService,
    private val userMapper: SysUserMapper,
    private val loginService: SysLoginService,
) : IAuthStrategy {
    companion object {
        private val log = KotlinLogging.logger {}
    }

    /**
     * 登录-第三方授权登录
     *
     * @param body     登录信息
     * @param client   客户端信息
     */
    override fun login(body: String, client: SysClientVo): LoginVo {
        val loginBody = JsonUtils.parseObject(body, SocialLoginBody::class.java)
        validate(loginBody)
        val response = SocialUtils.loginAuth(
            loginBody.source,
            loginBody.socialCode,
            loginBody.socialState,
            socialProperties
        )
        if (!response.ok()) {
            throw ServiceException(response.msg)
        }
        val authUserData = response.data

        val list = sysSocialService.selectByAuthId(authUserData.source + authUserData.uuid)
        if (CollUtil.isEmpty(list)) {
            throw ServiceException("你还没有绑定第三方账号，绑定后才可以登录！")
        }
        val social: SysSocialVo
        if (TenantHelper.isEnable()) {
            val opt = StreamUtils.findAny(list) { x ->
                x.tenantId == loginBody.tenantId
            }
            if (opt.isEmpty) {
                throw ServiceException("对不起，你没有权限登录当前租户！")
            }
            social = opt.get()
        } else {
            social = list[0]
        }
        val loginUser = TenantHelper.dynamic<LoginUser>(social.tenantId) {
            val user = loadUserByCondition(userMapper, SysUser::getUserId, social.userId, log)
            loginService.buildLoginUser(user)
        }.apply {
            clientKey = client.clientKey
            deviceType = client.deviceType
        }
        val model = createSaLoginModel(client)
        // 生成token
        LoginHelper.login(loginUser, model)

        return LoginVo().apply {
            accessToken = StpUtil.getTokenValue()
            expireIn = StpUtil.getTokenTimeout()
            clientId = client.clientId
        }
    }

}
